#pragma once

#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

namespace ns_log
{

#define SIZE 1024

#define INFO 0
#define DEBUG 1
#define WARNING 2
#define ERROR 3
#define FATAL 4

#define Screen 1
#define Onefile 2
#define Classfile 3

#define LogFile "log.txt"

    class Log
    {
    public:
        // 构造函数
        Log()
        {
            // 设置默认日志模式为向屏幕打印
            printMethod = Screen;
            path = "./log/";
        }

        // 调整日志模式
        void Enable(int method)
        {
            printMethod = method;
        }

        // 返回分级字符串
        std::string levelToString(int level)
        {
            switch (level)
            {
            case INFO:
                return "INFO";
            case DEBUG:
                return "DEBUG";
            case WARNING:
                return "WARNING";
            case ERROR:
                return "ERROR";
            case FATAL:
                return "FATAL";
            default:
                return "None";
            }
        }

        // 根据不同模式，向不同位置打印日志
        void printLog(int level, const std::string &logtxt)
        {
            switch (printMethod)
            {
            case Screen:
                std::cout << logtxt;
                break;
            case Onefile:
                printOneFile(LogFile, logtxt);
                break;
            case Classfile:
                printClassFile(level, logtxt);
                break;
            default:
                break;
            }
        }

        // 向一个文件中写入日志
        void printOneFile(const std::string &logname, const std::string &logtxt)
        {
            std::string _logname = path + logname;
            int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // "log.txt"
            if (fd < 0)
                return;
            write(fd, logtxt.c_str(), logtxt.size());
            close(fd);
        }

        // 向一个文件夹中写入日志
        void printClassFile(int level, const std::string &logtxt)
        {
            std::string filename = LogFile;
            filename += ".";
            filename += levelToString(level); // "log.txt.DEBUG/WARNING/FATAL"
            printOneFile(filename, logtxt);
        }

        ~Log()
        {
        }

        // 运算符重载 便于直接使用
        void operator()(int level, const char *format, ...)
        {
            time_t t = time(nullptr);
            struct tm *ctime = localtime(&t);

            // leftbuffer - 存储等级信息与日期信息
            char leftbuffer[SIZE];
            snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),
                     ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
                     ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

            // 将可变参数中传入的参数写入到rightbuffer中
            // rightbuffer - 存储用户提示
            va_list s;
            va_start(s, format);
            char rightbuffer[SIZE];
            vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
            va_end(s);

            // 格式：默认部分+自定义部分
            char logtxt[SIZE * 3];
            snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);

            printLog(level, logtxt);
        }

    private:
        int printMethod;
        std::string path;
    };

}

ns_log::Log lg;